package cn.changein.framework.modular.system.service;

import cn.changein.framework.base.auth.context.LoginContextHolder;
import cn.changein.framework.base.pojo.node.ZTreeNode;
import cn.changein.framework.base.pojo.page.PageFactory;
import cn.changein.framework.core.constant.Const;
import cn.changein.framework.core.constant.factory.ConstantFactory;
import cn.changein.framework.core.exception.enumeration.BizExceptionEnum;
import cn.changein.framework.core.log.LogObjectHolder;
import cn.changein.framework.kernel.model.exception.RequestEmptyException;
import cn.changein.framework.kernel.model.exception.ServiceException;
import cn.changein.framework.modular.system.entity.Relation;
import cn.changein.framework.modular.system.entity.Role;
import cn.changein.framework.modular.system.mapper.RelationMapper;
import cn.changein.framework.modular.system.mapper.RoleMapper;
import cn.changein.framework.modular.system.model.RoleDTO;
import cn.changein.framework.util.ToolUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.NonNull;
import org.apache.commons.compress.utils.Lists;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 角色表 服务实现类
 *

 * @date: 2020-02-20
 * @copyright: 广州澄境科技有限公司
 */
@Service
public class RoleService extends ServiceImpl<RoleMapper, Role> {

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RelationMapper relationMapper;

    @Resource
    private UserService userService;

    /**
     * 添加角色
     *
     * @param role
     */
    @Transactional(rollbackFor = Exception.class)
    public void addRole(Role role) {
        if (ToolUtil.isOneEmpty(role, role.getName(), role.getPid(), role.getDescription())) {
            throw new RequestEmptyException();
        }
        Role parentRole = getById(role.getPid());
        role.setRoleLevel(parentRole.getRoleLevel() + 1);
        role.setRoleId(null);

        this.save(role);
    }

    /**
     * 编辑角色
     *
     * @param roleDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void editRole(RoleDTO roleDTO) {

        if (ToolUtil.isOneEmpty(roleDTO, roleDTO.getName(), roleDTO.getPid(), roleDTO.getDescription())) {
            throw new RequestEmptyException();
        }

        Role old = this.getById(roleDTO.getRoleId());
        BeanUtil.copyProperties(roleDTO, old);
        Role parentRole = getById(old.getPid());
        if (parentRole.getRoleLevel() >= old.getRoleLevel()) {
            throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "父级角色错误");
        }
        old.setRoleLevel(parentRole.getRoleLevel() + 1);
        this.updateById(old);

    }

    /**
     * 设置某个角色的权限
     *
     * @param roleId 角色id
     * @param ids    权限的id
     */
    @Transactional(rollbackFor = Exception.class)
    public void setAuthority(Long roleId, String ids) {

        // 删除该角色所有的权限
        this.roleMapper.deleteRolesById(roleId);

        // 添加新的权限
        for (Long id : Convert.toLongArray(ids.split(","))) {
            Relation relation = new Relation();
            relation.setRoleId(roleId);
            relation.setMenuId(id);
            this.relationMapper.insert(relation);
        }

        // 刷新当前用户的权限
        userService.refreshCurrentUser();
    }

    /**
     * 删除角色
     *
     * @param roleId
     */
    @Transactional(rollbackFor = Exception.class)
    public void delRoleById(Long roleId) {

        if (ToolUtil.isEmpty(roleId)) {
            throw new ServiceException(BizExceptionEnum.REQUEST_NULL);
        }

        //不能删除超级管理员角色
        if (roleId.equals(Const.ADMIN_ROLE_ID)) {
            throw new ServiceException(BizExceptionEnum.CANT_DELETE_ADMIN);
        }

        //缓存被删除的角色名称
        LogObjectHolder.me().set(ConstantFactory.me().getSingleRoleName(roleId));

        //删除角色
        this.roleMapper.deleteById(roleId);

        //删除该角色所有的权限
        this.roleMapper.deleteRolesById(roleId);

    }

    /**
     * 根据条件查询角色列表
     *
     * @param condition
     */
    public Page<Map<String, Object>> selectRoles(String condition, List parentRoleIds) {
        Page<Map<String, Object>> page = new Page<>();
        page.setSize(Integer.MAX_VALUE);
        if (CollectionUtil.isEmpty(parentRoleIds)) {
            return new Page<>();
        }
        List<Role> roleList = this.listByIds(parentRoleIds);
        fetchChildRoleList(roleList);
        List<Map<String, Object>> roleListMap = Lists.newArrayList();
        while (CollectionUtil.isNotEmpty(roleList)) {
            List<Role> temp = Lists.newArrayList();
            roleList.forEach(role -> {
                if (CollectionUtil.isNotEmpty(role.getChildRoleList())) {
                    temp.addAll(role.getChildRoleList());
                }
                Map<String, Object> objectMap = BeanUtil.beanToMap(role);
                objectMap.put("currentRole", false);
                if (parentRoleIds.contains(role.getRoleId())) {
                    objectMap.put("currentRole", true);
                }
                roleListMap.add(objectMap);
            });
            roleList = temp;
        }
        page.setRecords(roleListMap);
        return page;
    }

    /**
     * 删除某个角色的所有权限
     *
     * @param roleId 角色id
     */
    public int deleteRolesById(Long roleId) {
        return this.baseMapper.deleteRolesById(roleId);
    }

    /**
     * 获取角色列表树
     */
    public List<ZTreeNode> roleTreeList() {
        return this.baseMapper.roleTreeList();
    }

    /**
     * 获取角色列表树
     *
     * @param roleId
     * @return
     */
    public List<ZTreeNode> roleTreeListByRoleId(Long[] roleId) {
        return this.baseMapper.roleTreeListByRoleId(roleId);
    }

    /**
     * 获取角色列表
     *
     * @param name
     * @return
     */
    public IPage listRole(String name) {
        Page pageContext = PageFactory.defaultPage();
        return baseMapper.listRole(pageContext, name);
    }

    public void fetchChildRoleList(List<Role> roleList) {
        roleList.forEach(role -> {
            role.setChildRoleList(findByParent(role));
            if (CollectionUtil.isNotEmpty(role.getChildRoleList())) {
                fetchChildRoleList(role.getChildRoleList());
            }
        });
    }

    public List<Role> findByParent(@NonNull Role role) {
        QueryWrapper<Role> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Role::getPid, role.getRoleId())
                .eq(Role::getRoleLevel, role.getRoleLevel() + 1);
        return super.list(wrapper);
    }

    /**
     * 过滤用户不存在的角色
     */
    public void filterUserRole(List<ZTreeNode> roleTreeList) {
        List<Long> roleIdList = LoginContextHolder.getContext().getUser().getRoleList();
        List<Role> roles = super.listByIds(roleIdList);
        this.fetchChildRoleList(roles);
        List<Role> roleList = Lists.newArrayList();
        while (CollectionUtil.isNotEmpty(roles)) {
            List<Role> temp = Lists.newArrayList();
            roles.forEach(role -> {
                if (CollectionUtil.isNotEmpty(role.getChildRoleList())) {
                    temp.addAll(role.getChildRoleList());
                }
                roleList.add(role);
            });
            roles = temp;
        }
        //用户的所有角色id
        List<Long> userAllRoleId = roleList.stream().map(Role::getRoleId).collect(Collectors.toList());
        roleTreeList.removeIf(zTreeNode -> !userAllRoleId.contains(zTreeNode.getId()));
    }
}

